<?php

namespace Chaosyeo\SolarEngine\User;

use Chaosyeo\SolarEngine\Arrayable;
use Chaosyeo\SolarEngine\Properties;

class User implements Arrayable
{
    const SOURCE_TYPE = 'api';

    const TYPE = 'userset';

    // PACKAGE_TYPE 枚举值
    const PACKAGE_TYPE_CHINESE = 1; // 数据存储区域中国大陆
    const PACKAGE_TYPE_OVERSEA = 2; // 数据存储区域海外

    const USERSET_TYPE_INIT                 = 'userInit';
    const USERSET_TYPE_UPDATE               = 'userUpdate';
    const USERSET_TYPE_ADD                  = 'userAdd';
    const USERSET_TYPE_UNSET                = 'userUnset';
    const USERSET_TYPE_APPEND               = 'userAppend';
    const USERSET_TYPE_DELETE_BY_ACCOUNT_ID = 'userDeleteByAccountId';
    const USERSET_TYPE_DELETE_BY_VISITOR_ID = 'userDeleteByVisitorId';

    protected $appkey;
    protected $sourceType;
    protected $type;
    protected $usersetType;
    protected $accountId;
    protected $visitorId;
    protected $eventId;
    protected $ts;
    protected $packageType;
    protected $idfa;
    protected $idfv;
    protected $uuid;
    protected $imei;
    protected $imei2;
    protected $gaid;
    protected $oaid;
    protected $androidId;
    protected $meid;
    protected $mac;
    protected $ua;
    protected $ip;
    protected $ipv6;
    public $properties;

    /**
     * @param string $usersetType 用户设置类型（必传）
     * @param string|null $accountId 账号ID（与访客ID至少传一个）
     * @param string|null $visitorId 访客ID（与账号ID至少传一个）
     * @param Properties|null $properties 属性对象
     * @param array $params 可选参数数组
     */
    public function __construct(
        int $packageType,
        string $usersetType     = self::USERSET_TYPE_INIT,
        ?string $accountId      = null,
        ?string $visitorId      = null,
        ?Properties $properties = null,
        array $params           = []
    ) {
        if (!in_array($packageType, [self::PACKAGE_TYPE_CHINESE, self::PACKAGE_TYPE_OVERSEA])) {
            throw new \InvalidArgumentException('Invalid package type');
        }

        if (empty($accountId) && empty($visitorId)) {
            throw new \InvalidArgumentException('Either account ID or visitor ID is required');
        }

        if (!empty($accountId) && strlen($accountId) > 128) {
            throw new \InvalidArgumentException('Account ID cannot exceed 128 characters');
        }

        if (!empty($visitorId) && strlen($visitorId) > 128) {
            throw new \InvalidArgumentException('Visitor ID cannot exceed 128 characters');
        }

        if (is_null($properties)) {
            $properties = new Properties();
        }

        $this->setUsersetType($usersetType);

        $this->packageType = $packageType;
        $this->sourceType  = self::SOURCE_TYPE;
        $this->type        = self::TYPE;
        $this->accountId   = $accountId;
        $this->visitorId   = $visitorId;
        $this->properties  = $properties;

        foreach ($params as $key => $value) {
            if (property_exists($this, $key)) {
                $this->$key = $value;
            }
        }
    }

    public function setUsersetType(string $type): self
    {
        if (!in_array($type, [
            self::USERSET_TYPE_INIT,
            self::USERSET_TYPE_UPDATE,
            self::USERSET_TYPE_ADD,
            self::USERSET_TYPE_UNSET,
            self::USERSET_TYPE_APPEND,
            self::USERSET_TYPE_DELETE_BY_ACCOUNT_ID,
            self::USERSET_TYPE_DELETE_BY_VISITOR_ID
        ])) {
            throw new \InvalidArgumentException('UsersetType is invalid');
        }
        $this->usersetType = $type;
        return $this;
    }

    /**
     * 获取所有非空属性
     * @return array
     */
    public function toArray(): array
    {
        $data = [];
        $vars = get_object_vars($this);
        array_walk($vars, function ($value, $key) use (&$data) {
            if (!is_null($value) && $key !== 'properties') {
                $key = '_' . strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $key));
                $data[$key] = $value;
            }
        });
        $data['properties'] = $this->properties->toArray();
        return $data;
    }
}